/* export interface PageQueryParams {
    page: number;

    size: number;

    prop?: string;

    order?: 'asc' | 'desc';

    [name: string]: any;
}

export interface PageResponse<T> {
    empty: boolean;

    first: boolean;

    last: boolean;

    number: number;

    numberOfElements: number;

    size: number;

    totalElements: number;

    totalPages: number;

    content: T[];
}

export interface PageDataConfig {
    size: number;
}

export type PageQueryFn<T> = (params: PageQueryParams) => Promise<PageResponse<T>>; */

export class PageData {
    constructor(queryFn, config) {
        this.queryFn = queryFn;
        Object.assign(this.config, config);
        this.params = { page: 0, size: this.config.size };
        this.size = this.config.size;
    }

    config = {
        size: 10
    };

    page = 0;

    size = 10;

    total = 0;

    loading = false;

    params;

    rows = [];

    hasMore = true;

    empty = false;

    hasError = false;

    queryFn;

    _load(params, reserved = false) {
        if (params) this.params = params;
        this.loading = true;
        if (!reserved) this.rows = [];
        return this.queryFn(this.params)
            .then((data) => {
                this.page = data?.numberOfElements;
                this.size = data?.size;
                this.total = data?.totalElements;
                this.rows = reserved ? merge(this.rows, data?.content) : data?.content;
                this.hasMore = !data?.last;
                this.empty = data?.empty;
                this.hasError = false;
            })
            .catch((e) => {
                this.hasError = true;
                throw e;
            })
            .finally(() => {
                this.loading = false;
            });

        function merge(source = [], target = [], key = 'id') {
            const set = new Set(source.map((v) => v.id));
            return [...source, ...target.filter((v) => !set.has(v.id))];
        }
    }

    load(params = {}) {
        this._load(Object.assign({ page: 0, size: this.params.size }, params));
    }

    sort(params = {}) {
        this._load(Object.assign({}, this.params, { page: 0, size: this.params.size }, params));
    }

    filter(params = {}) {
        const { prop, order } = this.params;
        this._load(Object.assign({ page: 0, size: this.params.size, prop, order }, params));
    }

    gotoPage(page = 0) {
        this._load(Object.assign({}, this.params, { page: page }));
    }

    gotoSize(size = 0) {
        this._load(Object.assign({}, this.params, { size: size }));
    }

    loadNext() {
        if (!this.hasMore || this.hasError || this.loading) return Promise.resolve();
        return this._load(Object.assign({}, this.params, { page: this.page === 0 ? 0 : this.params.page + 1 }), true);
    }

    reload(reset = true) {
        if (reset) {
            this.params.page = 0;
        }
        this._load();
    }
}
